const baseController = require('./base.js');
const yapi = require('../yapi.js');
const dubboInterfaceModel = require('../models/dubboInterface.js');
const dubboMethodModel = require('../models/dubboMethod.js');
// const dubboMethodModel = require('../models/interfaceMethod.js');
const dubboProjectModel = require('../models/dubboProject.js');
const caseModel = require('../models/dubboCase.js');
const userModel = require('../models/user.js');
const groupModel = require('../models/group.js');

function handleHeaders(values){
  let isfile = false,
      isHavaContentType = false;
  if (values.req_body_type === 'form') {
    values.req_body_form.forEach(item => {
      if (item.type === 'file') {
        isfile = true;
      }
    });

    values.req_headers.map(item => {
      if (item.name === 'Content-Type') {
        item.value = isfile ? 'multipart/form-data' : 'application/x-www-form-urlencoded';
        isHavaContentType = true;
      }
    });
    if (isHavaContentType === false) {
      values.req_headers.unshift({
        name: 'Content-Type',
        value: isfile ? 'multipart/form-data' : 'application/x-www-form-urlencoded'
      });
    }
  } else if (values.req_body_type === 'json') {
    values.req_headers
        ? values.req_headers.map(item => {
          if (item.name === 'Content-Type') {
            item.value = 'application/json';
            isHavaContentType = true;
          }
        })
        : [];
    if (isHavaContentType === false) {
      values.req_headers = values.req_headers || [];
      values.req_headers.unshift({
        name: 'Content-Type',
        value: 'application/json'
      });
    }
  }
}

class dubboInterfaceController extends baseController {
  constructor(ctx) {
    super(ctx);
    this.Model = yapi.getInst(dubboInterfaceModel);
    this.dubboProjectModel = yapi.getInst(dubboProjectModel);
    this.caseModel = yapi.getInst(caseModel);
    this.userModel = yapi.getInst(userModel);
    this.groupModel = yapi.getInst(groupModel);
    this.methodModel = yapi.getInst(dubboMethodModel);
  }

  // 添加dubbo接口
  async add(ctx) {
    let params = ctx.params;
    let projectid = params.projectid;
    let cname = params.cname;
    let classname = params.classname;

    if (!projectid) {
      return (ctx.body = yapi.commons.resReturn(null, 400, 'dubbo项目id不能为空'));
    }
    if (!cname) {
      return (ctx.body = yapi.commons.resReturn(null, 400, '接口名不能为空'));
    }
    if (!classname) {
      return (ctx.body = yapi.commons.resReturn(null, 400, '接口所属类名不能为空'));
    }

    if (!this.$tokenAuth) {
      let auth = await this.checkAuth(params.projectid, 'dubboproject', 'edit');

      if (!auth) {
        return (ctx.body = yapi.commons.resReturn(null, 40033, '没有权限'));
      }
    }

    handleHeaders(params);

    let checkRepeat = await this.Model.checkRepeat(params.projectid, params.classname);
    // let checkRepeat = await this.Model.checkRepeat(params.cname);

    if (checkRepeat > 0) {
      return (ctx.body = yapi.commons.resReturn(
          null,
          40022,
          '已存在的接口:' + params.classname
      ));
    }

    let data = Object.assign(params, {
      cname: params.cname,
      classname:params.classname,
      projectid: params.projectid, //左边的projectid对应的是表字段名，不能改成下划线
      desc: params.desc,
      cuserid: this.getUid(),
      ctime: yapi.commons.time(),
      euserid: this.getUid(),
      etime: yapi.commons.time(),
      status:0 //新增接口的状态默认值为 0，也就是设计中
    });

    /* ttc: 有bug的代码，待解决  */
    // 新建接口的人成为项目dev  如果不存在的话
    // 命令行导入时无法获知导入接口人的信息，其uid 为 999999
    // >ttc：这部分代码有bug，为了测试方便暂时注掉<
    // let uid = this.getUid();
    // console.log(uid);
    // console.log(this.getRole());

    // if (this.getRole() !== 'admin' && uid !== 999999) {
    //   let userdata = await yapi.commons.getUserdata(uid, 'dev');
    //   // 检查一下是否有这个人
    //   let check = await this.dubboProjectModel.checkMemberRepeat(params.projectid, uid);
    //   if (check === 0 && userdata) {
    //     await this.dubboProjectModel.addMember(params.projectid, [userdata]);
    //   }
    // }

    /* ^^^^^ 有bug的代码，待解决 ^^^^^ */

    let result = await this.Model.save(data);
    let logData = {
      dubbo_interface_id: Number(result._id),
      current:result,
      old:"old"
    };
    // result['interface_id'] = result._id; //能从result取出interface_id但是写入的data里还是看不见

    yapi.emitHook('interface_add', result).then();
    // 写记录
    let username = this.getUsername();
    yapi.commons.saveLog({
      content: `<a href="/user/profile/${this.getUid()}">${username}</a>添加了接口<a href="/dubboproject/${
          params.projectid
      }/interface/api/cat_${result._id}">${params.classname}</a>`,
      type: 'dubboproject',
      uid: this.getUid(),
      username:username,
      typeid: Number(params.projectid),
      data: logData
    });
    this.dubboProjectModel.up(params.projectid, { up_time: new Date().getTime()}).then();
    ctx.body = yapi.commons.resReturn(result);
  }

  // 保存
  // TODO

  // 获取接口
  async get(ctx) {
    let params = ctx.params;
    if (!params.id) {
      return (ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空'));
    }

    try {
     let result = await this.Model.get(params.id);
     if (this.$tokenAuth){
       if(params.projectid !== result.projectid){
         ctx.body = yapi.commons.resReturn(null, 400, 'token有误');
         return;
       }
     }
     if (!result) {
       return (ctx.body = yapi.commons.resReturn(null, 490, '该接口不存在'));
     }
     let userinfo = await this.userModel.findById(result.cuserid);
     let dubboProject = await this.dubboProjectModel.getBaseInfo(result.projectid);
     if (dubboProject.projecttype === 'private') {
       if ((await this.checkAuth(dubboProject._id, 'dubboproject', 'view')) !== true) {
         return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限'));
       }
     }
     yapi.emitHook('interface_get', result).then();
     result = result.toObject();
     if (userinfo) {
       result.username = userinfo.username;
     }
     ctx.body = yapi.commons.resReturn(result);
    } catch (err) {
      ctx.body = yapi.commons.resReturn(null, 402, err.message);
    }
  }

  // 接口列表
  async list(ctx) {
    let project_id = ctx.params.projectid;
    let page = ctx.request.query.page || 1,
        limit = ctx.request.query.limit || 10;
    let dubboProject = await this.dubboProjectModel.getBaseInfo(project_id);
    if (!dubboProject) {
      return (ctx.body = yapi.commons.resReturn(null, 407, '不存在的dubbo项目'));
    }
    if (dubboProject.projecttype === 'private') {
      if ((await this.checkAuth(dubboProject._id, 'dubboproject', 'view')) !== true) {
        return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限'));
      }
    }
    if (!project_id) {
      return (ctx.body = yapi.commons.resReturn(null, 400, 'dubbo id 不能为空'));
    }

    try {
      let result;
      if (limit === 'all') {
        result = await this.Model.list(project_id);
      } else {
        result = await this.Model.listWithPage(project_id, page, limit);
      }

      let count = await this.Model.listCount({ project_id });

      ctx.body = yapi.commons.resReturn({
        count: count,
        total: Math.ceil(count / limit),
        list: result
      });
      yapi.emitHook('interface_list', result).then();
    } catch (err) {
      ctx.body = yapi.commons.resReturn(null, 402, err.message);
    }
  }

  async downloadCrx(ctx) {
    let filename = 'crossRequest.zip';
    let dataBuffer = yapi.fs.readFileSync(
        yapi.path.join(yapi.WEBROOT, 'static/attachment/cross-request.zip')
    );
    ctx.set('Content-disposition', 'attachment; filename=' + filename);
    ctx.set('Content-Type', 'application/zip');
    ctx.body = dataBuffer;
  }

  // 删除接口
  async del(ctx) {
    try {
      let id = ctx.request.body.id;

      if (!id) {
        return (ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空'));
      }

      let data = await this.Model.get(id);

      if (data.cuserid != this.getUid()) {
        let auth = await this.checkAuth(data.projectid, 'dubboproject', 'danger');
        if (!auth) {
          return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限'));
        }
      }
      data['interface_id'] = data._id;
      let result = await this.Model.del(id);
      yapi.emitHook('interface_del', id).then();
      await this.caseModel.delByInterfaceId(id);
      let username = this.getUsername();
      yapi.commons.saveLog({
        content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口 "${data.cname}"`,
        type: 'dubboproject',
        uid: this.getUid(),
        username: username,
        typeid: data.projectid,
        data: data
      });
      this.dubboProjectModel.up(data.projectid, { up_time: new Date().getTime() }).then();
      ctx.body = yapi.commons.resReturn(result);
    } catch (err) {
      ctx.body = yapi.commons.resReturn(null, 402, err.message);
    }
  }



  /* TTC ADD */

  async listByMenu(ctx){
    let project_id = ctx.params.projectid;
    if (!project_id) {
      return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
    }
    let project = await this.dubboProjectModel.getBaseInfo(project_id);
    if (!project) {
      return (ctx.body = yapi.commons.resReturn(null, 406, '不存在的项目'));
    }
    if (project.project_type === 'private') {
      if ((await this.checkAuth(project._id, 'project', 'view')) !== true) {
        return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限'));
      }
    }

    try {
      let result = await this.Model.list(project_id),
          newResult = [];
      for (let i = 0, item, list; i < result.length; i++) {
        item = result[i].toObject();
        list = await this.methodModel.listByInfId(item._id);
        for (let j = 0; j < list.length; j++) {
          list[j] = list[j].toObject();
        }

        item.list = list;
        newResult[i] = item;
      }
      ctx.body = yapi.commons.resReturn(newResult);
    } catch (err) {
      ctx.body = yapi.commons.resReturn(null, 402, err.message);
    }
  }


  /**
   * 此方法暂时弃用，现用add(ctx)方法
   * @param ctx
   * @returns {Promise<{errcode, data, errmsg}>}
   */
  async addInterface(ctx){
    try {
      let params = ctx.request.body;
      params = yapi.commons.handleParams(params, {
        cname: 'string',
        classname: 'string',
        projectid: 'number',
        desc: 'string'
      });

      if (!params.projectid) {
        return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
      }
      if (!this.$tokenAuth) {
        let auth = await this.checkAuth(params.projectid, 'dubboproject', 'edit');
        if (!auth) {
          return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限'));
        }
      }

      if (!params.cname) {
        return (ctx.body = yapi.commons.resReturn(null, 400, '名称不能为空'));
      }

      let result = await this.Model.save({
        cname: params.cname,
        classname:params.classname,
        projectid: params.projectid,
        desc: params.desc,
        cuserid: this.getUid(),
        ctime: yapi.commons.time()
        // etime: yapi.commons.time()
      });

      let logData = {
        dubbo_interface_id: Number(result._id),
        current:result
      };

      let username = this.getUsername();
      yapi.commons.saveLog({
        content: `<a href="/user/profile/${this.getUid()}">${username}</a> 添加了接口  <a href="/dubboproject/${
            params.projectid
        }/interface/api/cat_${result._id}">${params.name}</a>`,
        type: 'dubboproject',
        uid: this.getUid(),
        username: username,
        typeid: params.projectid,
        data: logData
      });

      ctx.body = yapi.commons.resReturn(result);
    } catch (e) {
      ctx.body = yapi.commons.resReturn(null, 402, e.message);
    }
  }


  /**
   * 更新接口的基本信息
   * @param ctx
   * @returns {Promise<{errcode, data, errmsg}>}
   */
  async updateInterface(ctx){

    try {
      let params = ctx.request.body;

      let username = this.getUsername();
      let inf = await this.Model.get(params.infid);

      let auth = await this.checkAuth(inf.projectid, 'dubboproject', 'edit');
      if (!auth) {
        return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限'));
      }

      // ttc：接口类名查重，但是如果没有更改类名，就不查重
      if(inf.classname != params.classname) {
        let checkRepeat = await this.Model.checkRepeat(inf.projectid, params.classname);
        if (checkRepeat > 0) {
          return (ctx.body = yapi.commons.resReturn(
            null,
            40022,
            '已存在的接口:' + params.classname
          ));
        }
      }

      // 先获取老数据
      let old = await this.Model.get(params.infid);

      // 更新
      await this.Model.up(params.infid, {
        cname: params.cname,
        desc: params.desc,
        // onlinedate: params.onlinedate?new Date(params.onlinedate):'',
        onlinedate:params.onlinedate,
        classname:params.classname,
        status:params.status,
        etime: yapi.commons.time(),
        euserid: this.getUid()
      });

      // 再获取新数据
      let result = await this.Model.get(params.infid);
        let logData = {
          type:'interface_up',
          dubbo_interface_id: Number(params.infid),
          current: result,
          old: old
      };

      yapi.commons.saveLog({
        content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了接口 <a href="/dubboproject/${
            inf.projectid
        }/interface/api/cat_${params.infid}">${inf.classname}</a>`,
        type: 'dubboproject',
        uid: this.getUid(),
        username: username,
        typeid: inf.projectid,
        data: logData
      });

      ctx.body = yapi.commons.resReturn(result);
      // console.log('修改成功！！！！！')
    } catch (e) {
      ctx.body = yapi.commons.resReturn(null, 400, e.message);
    }

  }

  /**
   * 删除接口
   * @param ctx
   * @returns {Promise<{errcode, data, errmsg}>}
   */
  async delInterface(ctx){
    try {
      let id = ctx.request.body.id;
      let infData = await this.Model.get(id);
      if (!infData) {
        ctx.body = yapi.commons.resReturn(null, 400, '不存在的分类');
      }

      if (infData.cuserid !== this.getUid()) {
        let auth = await this.checkAuth(infData.projectid, 'dubboproject', 'danger');
        if (!auth) {
          return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限'));
        }
      }

      // let interfaceData = await this.Model.listByCatid(id); //原来是从分类中找出接口信息
      // let methodData = await this.methodModel.listByInfId(id);

      // console.log(methodData);

      // methodData.forEach(async item => {
      //   try {
      //     // yapi.emitHook('interface_del', item._id).then();
      //     // await this.caseModel.delByInterfaceId(item._id);
      //     await  this.methodModel.del(item._id)
      //   } catch (e) {
      //     yapi.commons.log(e.message, 'error');
      //   }
      // });

      await this.Model.del(id);
      let r = await this.methodModel.delByInfId(id);

      // let logData = {
      //   dubbo_interface_id: Number(id)
      // };

      let username = this.getUsername();
      yapi.commons.saveLog({
        content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口 "${
          infData.classname
        }" 及该接口下的方法`,
        type: 'dubboproject',
        uid: this.getUid(),
        username: username,
        typeid: infData.projectid
        // data: logData //暂时不需要logData
      });

      return (ctx.body = yapi.commons.resReturn(r));
    } catch (e) {
      yapi.commons.resReturn(null, 400, e.message);
    }
  }

  /**
   * 获取接口的基本信息infBaseInfo和接口所属的方法列表methodList
   * @param ctx
   * @returns {Promise<void>}
   */
  async getInfo(ctx){

    let interfaceId = ctx.params._id;

    try {
      let infBaseInfo = await this.Model.get(interfaceId);

      let item = infBaseInfo.toObject();
      let methodList = await this.methodModel.listByInfId(item._id);
      for (let j = 0; j < methodList.length; j++) {
        methodList[j] = methodList[j].toObject();
      }
      // 返回的数据包括了 ｛接口的基本信息 和 接口所含方法列表｝
      // let result = [infBaseInfo,methodList];
      let result = {infBaseInfo,methodList};
      ctx.body = yapi.commons.resReturn(result);
    } catch (err) {
      ctx.body = yapi.commons.resReturn(null, 402, err.message);
    }
  }

  async getInfByCondition(ctx){
    let condition = ctx.request.body;

    let projectid = condition.projectid;
    let onlinedate = condition.onlinedate;
    let status = condition.status;
    let classname = condition.classname;
    // 模糊查询处理
    let classRegex = new RegExp(classname);

    let result = null;

    //检查接口类名框传来的值是否包含中文，如果包含中文，则根据cname查，否则根据classname查
    function isChn(str) {
      let reg = /.*[\u4e00-\u9fa5]+.*$/;
      return reg.test(str);
    }

    try{
      // 000：当onlinedate和status、classname均为空，则按projectid返回所有的接口
      if(onlinedate == null && status == null && classname === ""){
        result = await this.Model.listByProject(projectid);
      }
      // 001：当onlinedate和status为空，classname不为空（字符串）
      else if(onlinedate == null && status == null && classname !== ""){
        if(isChn(classname)) {
          result = await this.Model.listByCNClassRegex(projectid, classRegex);
        }
        else{
          result = await this.Model.listByENClassRegex(projectid, classRegex);
        }
      }
      // 010：当onlinedate和classname为空，status不为空
      else if(onlinedate == null && status != null && classname === ""){
        result = await this.Model.listByStatus(projectid,status);
      }
      // 011:当onlinedate为空，status和classname不为空
      else if(onlinedate == null && status != null && classname !== ""){
        if(isChn(classname)) {
          result = await this.Model.listBySnCNC(projectid, status, classRegex);
        }
        else{
          result = await this.Model.listBySnENC(projectid, status, classRegex);
        }
      }
      // 100：当onlinedate不为空，status和classname为空
      else if(onlinedate != null && status == null && classname === ""){
        result = await this.Model.listByOnlinedate(projectid,onlinedate);
      }
      // 101：onlinedate和classname不为空，status为空
      else if(onlinedate != null && status == null && classname !== ""){
        if(isChn(classname)){
          result = await this.Model.listByOnCNC(projectid,onlinedate,classRegex);
        }
        else{
          result = await this.Model.listByOnENC(projectid,onlinedate,classRegex);
        }
      }
      // 110：onlinedate和status不为空，classname为空
      else if(onlinedate != null && status != null && classname === ""){
        result = await this.Model.listByOnS(projectid,onlinedate,status);
      }
      // 111：当三个条件均不空
      else{
        if(isChn(classname)) {
          result = await this.Model.listByOnSnCNC(projectid, onlinedate, status, classRegex);
        }
        else{
          result = await this.Model.listByOnSnENC(projectid, onlinedate, status, classRegex);
        }
      }

      ctx.body = yapi.commons.resReturn(result);
    } catch(e) {
      return (ctx.body = yapi.commons.resReturn(null, 402, e.message));
    }
  }

  /* TTC ADD ^^^^ */
  
  // //SH test_1
  // async getTxt(ctx) {
  //   let params = ctx.request.body;
  //   let pid = params.pid;
  //   let date = new Date(params.time).getTime();
  //   let project = await this.dubboProjectModel.get(pid);
  //   let interfaceArr = await this.Model.listByPid(pid);
  //   let methodArr = new Array();
  //   if(interfaceArr.length > 0){
  //     for(let i=0; i<interfaceArr.length; i++){
  //       let result = await this.methodModel.listByInfId(interfaceArr[i]._id)
  //       methodArr[i] = result;
  //     }
      
  //     let result_interface = interfaceArr;
  //     let result_method = methodArr
  //     let serviceMap = {};
  //     let routeMap = {};
  //     let aTxt = {};
  //     let bTxt = {};
  //     for(let m=0; m<result_interface.length; m++){
  //       if (result_interface[m].onlinedate <= date) {
  //         let aaTxt = {
  //           'clientTimeout': 30000,
  //           'maxWaittimeForfsaddress': 1000,
  //           'methodList': [],
  //           'serviceGroup': project.dgroup,
  //           'serviceName': result_interface[m].classname,
  //           'version': '1.0.0'
  //         };
  //         let name = aaTxt.serviceName.split('.');
  //         let temp = (aaTxt.serviceGroup + '.' + name[name.length-1] + '.v1.0.0');
  //         for(let n=0; n<result_method[m].length; n++){
  //           let online = new Date(result_method[m][n].onlinedate).getTime();
  //           if (online <= date) {
  //             aaTxt.methodList.push(( result_method[m][n].mname + '::' + result_method[m][n].inname ));
  //             if (result_method[m][n].ischl === 1){
  //               let title = result_method[m][n].chltype;
  //               bTxt[title] = ( temp + '::' +  result_method[m][n].mname );
  //             }
  //           }
  //         }
  //         aTxt[ temp ] = aaTxt;
  //       }
  //     }
  //     serviceMap[ 'serviceMap' ] = aTxt;
  //     routeMap[ 'routeMap' ] = bTxt;
  //     let map_1 = JSON.stringify(serviceMap, null, 4);
  //     let map_2 = JSON.stringify(routeMap, null, 4);

  //     fs.mkdir('txt', e => {
  //       if (e) {
  //         return (ctx.body = yapi.commons.resReturn(null, 400, '目录创建失败！'));
  //       }
  //     });

  //     fs.writeFile('txt/serviceMap.txt', map_1, er => {
  //       if (er) {
  //         return (ctx.body = yapi.commons.resReturn(null, 400, '文件创建失败！'));
  //       } else {
  //         fs.writeFile('txt/routeMap.txt', map_2, err => {
  //           if (err){
  //             return (ctx.body = yapi.commons.resReturn(null, 400, '文件打包失败！'));
  //           } else {
  //             let zipper = require("zip-local");
  //             zipper.sync.zip("txt").compress().save("txt.zip");
  //           }
  //         });
  //       }
  //     })

  //     ctx.body = yapi.commons.resReturn({
  //       // method: methodArr,
  //       // interface: interfaceArr
  //     });
  //   } else {
  //     return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空'));
  //   }
  // }

  //SH test_2
  async getTxt(ctx) {

    let params = ctx.request.body;
    let pid = params.pid;
    let methodArr = params.ids;
    let interfaceArr = [];
    let result_method = [];
    let result_interface = [];
    let user_method = [];
    let user_interface = [];
    let name;
    let group;

    try{
      for (let i=0; i<methodArr.length; i++){
        let result = await this.methodModel.get(methodArr[i]);
        let temp_1 = await this.userModel.findByUid(result.cuserid);
        let temp_2 = await this.userModel.findByUid(result.euserid);
        let user = {
          'cuser': temp_1.username,
          'euser': temp_2.username
        }
        result_method.push(result);
        user_method.push(user);
        interfaceArr.push(result.infid);
      }
      interfaceArr = Array.from(new Set(interfaceArr));
      for (let j=0; j<interfaceArr.length; j++){
        let result = await this.Model.get(interfaceArr[j]);
        let temp_1 = await this.userModel.findByUid(result.cuserid);
        let temp_2 = await this.userModel.findByUid(result.euserid);
        let user = {
          'cuser': temp_1.username,
          'euser': temp_2.username
        }
        result_interface.push(result);
        user_interface.push(user);
      }
  
      let project = await this.dubboProjectModel.get(pid);
      name = project.enname;
      group = project.dgroup;
  
      ctx.body = yapi.commons.resReturn({
        method: result_method,
        interface: result_interface,
        user_1: user_interface,
        user_2: user_method,
        name: name,
        group: group
      });
    } catch(e) {
      return (ctx.body = yapi.commons.resReturn(null, 402, e.message));
    }
  }
}
module.exports = dubboInterfaceController;